<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>AlloyFinger</title>
    <meta name="generator" content="VuePress 1.5.2">
    <link rel="apple-touch-icon" href="/blog/apple-touch-icon.png">
    <link rel="icon" href="/blog/favicon.ico">
    <link rel="manifest" href="/blog/manifest.json">
    <link rel="mask-icon" href="/blog/icons/icon.svg" color="#ffffff">
    <meta name="description" content="可能是全网最给力的前端博客">
    <meta name="theme-color" content="#ffffff">
    <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="default">
    <meta name="msapplication-TileImage" content="/icons/icon-144x144.png">
    <link rel="preload" href="/blog/assets/css/0.styles.3f022aa2.css" as="style"><link rel="preload" href="/blog/assets/js/app.7fa07907.js" as="script"><link rel="preload" href="/blog/assets/js/2.b6c629b5.js" as="script"><link rel="preload" href="/blog/assets/js/15.e91e78ed.js" as="script"><link rel="preload" href="/blog/assets/js/4.1dbf8b08.js" as="script"><link rel="preload" href="/blog/assets/js/3.589a64d8.js" as="script"><link rel="prefetch" href="/blog/assets/js/10.8e59817e.js"><link rel="prefetch" href="/blog/assets/js/11.34cd2f44.js"><link rel="prefetch" href="/blog/assets/js/12.445d88fd.js"><link rel="prefetch" href="/blog/assets/js/13.e6460b96.js"><link rel="prefetch" href="/blog/assets/js/14.d0ee0fcf.js"><link rel="prefetch" href="/blog/assets/js/16.8310de97.js"><link rel="prefetch" href="/blog/assets/js/17.6ca97902.js"><link rel="prefetch" href="/blog/assets/js/18.a82e534b.js"><link rel="prefetch" href="/blog/assets/js/19.e3a914ee.js"><link rel="prefetch" href="/blog/assets/js/20.6db77b80.js"><link rel="prefetch" href="/blog/assets/js/21.e705be23.js"><link rel="prefetch" href="/blog/assets/js/22.efc39414.js"><link rel="prefetch" href="/blog/assets/js/23.5f4c7658.js"><link rel="prefetch" href="/blog/assets/js/24.359a62e4.js"><link rel="prefetch" href="/blog/assets/js/25.c49ef7a9.js"><link rel="prefetch" href="/blog/assets/js/26.8d45691f.js"><link rel="prefetch" href="/blog/assets/js/27.364b1802.js"><link rel="prefetch" href="/blog/assets/js/28.485228c0.js"><link rel="prefetch" href="/blog/assets/js/29.0ee8fc42.js"><link rel="prefetch" href="/blog/assets/js/30.465920a7.js"><link rel="prefetch" href="/blog/assets/js/5.9253897f.js"><link rel="prefetch" href="/blog/assets/js/6.4c1f13e3.js"><link rel="prefetch" href="/blog/assets/js/7.bc1839d0.js"><link rel="prefetch" href="/blog/assets/js/8.611f5ec5.js"><link rel="prefetch" href="/blog/assets/js/9.5813bb74.js">
    <link rel="stylesheet" href="/blog/assets/css/0.styles.3f022aa2.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/blog/" class="home-link router-link-active"><img src="/blog/app.png" alt="卢本伟广场" class="logo"> <span class="site-name can-hide">卢本伟广场</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/blog/dsm/" class="nav-link router-link-active">
  歪比歪比
</a></div><div class="nav-item"><a href="/blog/lbw/" class="nav-link">
  歪比吧卜
</a></div> <!----></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/blog/dsm/" class="nav-link router-link-active">
  歪比歪比
</a></div><div class="nav-item"><a href="/blog/lbw/" class="nav-link">
  歪比吧卜
</a></div> <!----></nav>  <ul class="sidebar-links"><li><a href="/blog/dsm/" aria-current="page" class="sidebar-link">前端自我修养</a></li><li><a href="/blog/dsm/algorithm.html" class="sidebar-link">前端面试算法</a></li><li><a href="/blog/dsm/jsbook.html" class="sidebar-link">JS高级程序设计</a></li><li><a href="/blog/dsm/cc150.html" class="sidebar-link">程序员面试金典</a></li><li><a href="/blog/dsm/pattern.html" class="sidebar-link">前端设计模式</a></li><li><a href="/blog/dsm/architecture.html" class="sidebar-link">前端工程架构</a></li><li><a href="/blog/dsm/protocol.html" class="sidebar-link">计算机网络</a></li><li><a href="/blog/dsm/node.html" class="sidebar-link">服务端开发</a></li><li><a href="/blog/dsm/webgl.html" class="sidebar-link">图形3D开发</a></li><li><a href="/blog/dsm/lodash.html" class="sidebar-link">jQuery / Lodash</a></li><li><a href="/blog/dsm/finger.html" aria-current="page" class="active sidebar-link">AlloyFinger</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/blog/dsm/finger.html#tap" class="sidebar-link">Tap</a></li><li class="sidebar-sub-header"><a href="/blog/dsm/finger.html#multipointstart" class="sidebar-link">MultipointStart</a></li><li class="sidebar-sub-header"><a href="/blog/dsm/finger.html#longtap" class="sidebar-link">LongTap</a></li><li class="sidebar-sub-header"><a href="/blog/dsm/finger.html#swipe" class="sidebar-link">Swipe</a></li><li class="sidebar-sub-header"><a href="/blog/dsm/finger.html#pinch" class="sidebar-link">Pinch</a></li><li class="sidebar-sub-header"><a href="/blog/dsm/finger.html#rotate" class="sidebar-link">Rotate</a></li><li class="sidebar-sub-header"><a href="/blog/dsm/finger.html#pressmove" class="sidebar-link">PressMove</a></li><li class="sidebar-sub-header"><a href="/blog/dsm/finger.html#multipointend" class="sidebar-link">MultipointEnd</a></li><li class="sidebar-sub-header"><a href="/blog/dsm/finger.html#doubletap" class="sidebar-link">DoubleTap</a></li><li class="sidebar-sub-header"><a href="/blog/dsm/finger.html#singletap" class="sidebar-link">SingleTap</a></li><li class="sidebar-sub-header"><a href="/blog/dsm/finger.html#touchstart" class="sidebar-link">TouchStart</a></li><li class="sidebar-sub-header"><a href="/blog/dsm/finger.html#touchmove" class="sidebar-link">TouchMove</a></li><li class="sidebar-sub-header"><a href="/blog/dsm/finger.html#touchend" class="sidebar-link">TouchEnd</a></li><li class="sidebar-sub-header"><a href="/blog/dsm/finger.html#touchcancel" class="sidebar-link">TouchCancel</a></li></ul></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="alloyfinger"><a href="#alloyfinger" class="header-anchor">#</a> AlloyFinger</h1> <img id="h2CenterTopImg" src="/blog/images/IMG_8892.JPG"> <h2 id="tap"><a href="#tap" class="header-anchor">#</a> Tap</h2> <div class="compare" data-v-2a5edddd><div class="left" data-v-2a5edddd><p data-v-2a5edddd>效果</p> <div class="jq" data-v-2a5edddd></div> <div class="effect" data-v-2a5edddd><img id="finger" src="/blog/images/IMG_8898.gif" data-v-2a5edddd></div></div> <div class="right" data-v-2a5edddd><p data-v-2a5edddd>模拟</p> <div class="js" data-v-2a5edddd><pre data-v-2a5edddd><code class="javascript" data-v-2a5edddd>class AlloyFinger {
  constructor(el, option) {
    this.el = typeof el == &quot;string&quot; ? document.querySelector(el) : el
    this.el.addEventListener(&quot;touchstart&quot;, this.start, false)
    this.el.addEventListener(&quot;touchmove&quot;, this.move, false)
    this.el.addEventListener(&quot;touchend&quot;, this.end, false)
    this.tap = new Observer(this.el)
    this.tap.add(option.tap || function () {})
  }
  start(evt) {
    if (!evt.touches) return
    let len = evt.touches.length
    if (len === 1) {
      this.x1 = evt.touches[0].pageX;
      this.y1 = evt.touches[0].pageY;
    }
  }
  move(evt) {
    if (!evt.touches) return
    let len = evt.touches.length
    if (len === 1) {
      this.x2 = evt.touches[0].pageX;
      this.y2 = evt.touches[0].pageY;
    }
  }
  end(evt) {
    if (!evt.changedTouches) return
    if ((this.x2 &amp;&amp; Math.abs(this.x1 - this.x2) &lt;= 30) &amp;&amp;
      (this.y2 &amp;&amp; Math.abs(this.y1 - this.y2) &lt;= 30)) {
      this.tap.dispatch(evt, this.el)
    }
  }
}</code></pre></div> <div class="css" data-v-2a5edddd></div></div></div> <h2 id="multipointstart"><a href="#multipointstart" class="header-anchor">#</a> MultipointStart</h2> <div class="compare" data-v-2a5edddd><div class="left" data-v-2a5edddd><p data-v-2a5edddd>效果</p> <div class="jq" data-v-2a5edddd></div> <div class="effect" data-v-2a5edddd><img id="finger" src="/blog/images/IMG_8898.gif" data-v-2a5edddd></div></div> <div class="right" data-v-2a5edddd><p data-v-2a5edddd>模拟</p> <div class="js" data-v-2a5edddd><pre data-v-2a5edddd><code class="javascript" data-v-2a5edddd>class AlloyFinger{
    constructor(el, option) {
        this.el = typeof el == &quot;string&quot; ? document.querySelector(el) : el
        this.el.addEventListener(&quot;touchstart&quot;, this.start, false);
        this.multipointStart = new Observer(this.el)
        this.multipointStart.add(option.multipointStart||function(){})
    }
    start(evt) {
        if (!evt.touches) return
        if (evt.touches.length &gt; 1) this.multipointStart.dispatch(evt, this.el)
    }
}</code></pre></div> <div class="css" data-v-2a5edddd></div></div></div> <h2 id="longtap"><a href="#longtap" class="header-anchor">#</a> LongTap</h2> <div class="compare" data-v-2a5edddd><div class="left" data-v-2a5edddd><p data-v-2a5edddd>效果</p> <div class="jq" data-v-2a5edddd></div> <div class="effect" data-v-2a5edddd><img id="finger" src="/blog/images/IMG_8898.gif" data-v-2a5edddd></div></div> <div class="right" data-v-2a5edddd><p data-v-2a5edddd>模拟</p> <div class="js" data-v-2a5edddd><pre data-v-2a5edddd><code class="javascript" data-v-2a5edddd>class AlloyFinger{
    constructor(el, option) {
        this.el = typeof el == &quot;string&quot; ? document.querySelector(el) : el
        this.el.addEventListener(&quot;touchstart&quot;, this.start, false);
        this.el.addEventListener(&quot;touchend&quot;, this.end, false);
        this.longTap = new Observer(this.el)
        this.longTap.add(option.longTap || function () {})
    }
    start(evt) {
        if (!evt.touches) return
        this.longTapTimeout = setTimeout(() =&gt; this.longTap.dispatch(evt, this.el), 750);
    }
    end(evt) {
        if (!evt.changedTouches) return;
        this._cancelLongTap();
    }
    _cancelLongTap() {
        clearTimeout(this.longTapTimeout);
    }
}</code></pre></div> <div class="css" data-v-2a5edddd></div></div></div> <h2 id="swipe"><a href="#swipe" class="header-anchor">#</a> Swipe</h2> <div class="compare" data-v-2a5edddd><div class="left" data-v-2a5edddd><p data-v-2a5edddd>效果</p> <div class="jq" data-v-2a5edddd></div> <div class="effect" data-v-2a5edddd><img id="finger" src="/blog/images/IMG_8898.gif" data-v-2a5edddd></div></div> <div class="right" data-v-2a5edddd><p data-v-2a5edddd>模拟</p> <div class="js" data-v-2a5edddd><pre data-v-2a5edddd><code class="javascript" data-v-2a5edddd>class AlloyFinger {
  constructor(el, option) {
    this.el = typeof el == &quot;string&quot; ? document.querySelector(el) : el
    this.el.addEventListener(&quot;touchstart&quot;, this.start, false)
    this.el.addEventListener(&quot;touchmove&quot;, this.move, false)
    this.el.addEventListener(&quot;touchend&quot;, this.end, false)
    this.swipe = new Observer(this.el)
    this.swipe.add(option.swipe || function () {})
  }
  start(evt) {
    if (!evt.touches) return
    let len = evt.touches.length
    if (len === 1) {
      this.x1 = evt.touches[0].pageX;
      this.y1 = evt.touches[0].pageY;
    }
  }
  move(evt) {
    if (!evt.touches) return
    let len = evt.touches.length
    if (len === 1) {
      this.x2 = evt.touches[0].pageX;
      this.y2 = evt.touches[0].pageY;
    }
  }
  end(evt) {
    if (!evt.changedTouches) return
    if ((this.x2 &amp;&amp; Math.abs(this.x1 - this.x2) &gt; 30) ||
      (this.y2 &amp;&amp; Math.abs(this.y1 - this.y2) &gt; 30)) {
      evt.direction = this._swipeDirection(this.x1, this.x2, this.y1, this.y2);
      this.swipeTimeout = setTimeout(() =&gt; this.swipe.dispatch(evt, this.el), 0)
    }
  }
}
function _swipeDirection(x1, x2, y1, y2) {
  return Math.abs(x1 - x2) &gt;= Math.abs(y1 - y2) ? (x1 - x2 &gt; 0 ? 'Left' : 'Right') : (y1 - y2 &gt; 0 ? 'Up' : 'Down')
}</code></pre></div> <div class="css" data-v-2a5edddd></div></div></div> <h2 id="pinch"><a href="#pinch" class="header-anchor">#</a> Pinch</h2> <div class="compare" data-v-2a5edddd><div class="left" data-v-2a5edddd><p data-v-2a5edddd>效果</p> <div class="jq" data-v-2a5edddd></div> <div class="effect" data-v-2a5edddd><img id="finger" src="/blog/images/IMG_8898.gif" data-v-2a5edddd></div></div> <div class="right" data-v-2a5edddd><p data-v-2a5edddd>模拟</p> <div class="js" data-v-2a5edddd><pre data-v-2a5edddd><code class="javascript" data-v-2a5edddd>class AlloyFinger {
  constructor(el, option) {
    this.el = typeof el == &quot;string&quot; ? document.querySelector(el) : el
    this.el.addEventListener(&quot;touchstart&quot;, this.start, false)
    this.el.addEventListener(&quot;touchmove&quot;, this.move, false)
    this.el.addEventListener(&quot;touchend&quot;, this.end, false)
    this.pinch = new Observer(this.el)
    this.pinch.add(option.pinch || function () {})
  }
  start(evt) {
    if (!evt.touches) return;
    let len = evt.touches.length
    if (len &gt; 1) this.preV = {
      x: evt.touches[1].pageX - evt.touches[0].pageX,
      y: evt.touches[1].pageY - evt.touches[0].pageY
    }
  }
  move(evt) {
    if (!evt.touches) return
    let len = evt.touches.length
    if (len &gt; 1) this.curV = {
      x: evt.touches[1].pageX - evt.touches[0].pageX,
      y: evt.touches[1].pageY - evt.touches[0].pageY
    }
  }
  end(evt) {
    evt.zoom = getLen(this.curV) / getLen(this.preV)
    evt.zoom &amp;&amp; this.pinch.dispatch(evt, this.el)
  }
}
function getLen(v) {
  return Math.sqrt(v.x * v.x + v.y * v.y);
}</code></pre></div> <div class="css" data-v-2a5edddd></div></div></div> <h2 id="rotate"><a href="#rotate" class="header-anchor">#</a> Rotate</h2> <div class="compare" data-v-2a5edddd><div class="left" data-v-2a5edddd><p data-v-2a5edddd>效果</p> <div class="jq" data-v-2a5edddd></div> <div class="effect" data-v-2a5edddd><img id="finger" src="/blog/images/IMG_8898.gif" data-v-2a5edddd></div></div> <div class="right" data-v-2a5edddd><p data-v-2a5edddd>模拟</p> <div class="js" data-v-2a5edddd><pre data-v-2a5edddd><code class="javascript" data-v-2a5edddd>class AlloyFinger {
  constructor(el, option) {
    this.el = typeof el == &quot;string&quot; ? document.querySelector(el) : el
    this.el.addEventListener(&quot;touchstart&quot;, this.start, false)
    this.el.addEventListener(&quot;touchmove&quot;, this.move, false)
    this.el.addEventListener(&quot;touchend&quot;, this.end, false)
    this.rotate = new Observer(this.el)
    this.rotate.add(option.rotate || function () {})
  }
  start(evt) {
    if (!evt.touches) return;
    let len = evt.touches.length
    if (len &gt; 1) this.preV = {
      x: evt.touches[1].pageX - evt.touches[0].pageX,
      y: evt.touches[1].pageY - evt.touches[0].pageY
    }
  }
  move(evt) {
    if (!evt.touches) return
    let len = evt.touches.length
    if (len &gt; 1) this.curV = {
      x: evt.touches[1].pageX - evt.touches[0].pageX,
      y: evt.touches[1].pageY - evt.touches[0].pageY
    }
  }
  end(evt) {
    evt.angle = getRotateAngle(this.curV, this.preV);
    evt.angle &amp;&amp; this.rotate.dispatch(evt, this.el);
  }
}
function dot(v1, v2) {
  return v1.x * v2.x + v1.y * v2.y;
}
function getAngle(v1, v2) {
  let mr = getLen(v1) * getLen(v2);
  if (mr === 0) return 0;
  let r = dot(v1, v2) / mr;
  if (r &gt; 1) r = 1;
  return Math.acos(r);
}
function cross(v1, v2) {
  return v1.x * v2.y - v2.x * v1.y;
}
function getRotateAngle(v1, v2) {
  let angle = getAngle(v1, v2);
  if (cross(v1, v2) &gt; 0) {
    angle *= -1;
  }
  return angle * 180 / Math.PI;
}</code></pre></div> <div class="css" data-v-2a5edddd></div></div></div> <h2 id="pressmove"><a href="#pressmove" class="header-anchor">#</a> PressMove</h2> <div class="compare" data-v-2a5edddd><div class="left" data-v-2a5edddd><p data-v-2a5edddd>效果</p> <div class="jq" data-v-2a5edddd></div> <div class="effect" data-v-2a5edddd><img id="finger" src="/blog/images/IMG_8898.gif" data-v-2a5edddd></div></div> <div class="right" data-v-2a5edddd><p data-v-2a5edddd>模拟</p> <div class="js" data-v-2a5edddd><pre data-v-2a5edddd><code class="javascript" data-v-2a5edddd>class AlloyFinger {
  constructor(el, option) {
    this.el = typeof el == &quot;string&quot; ? document.querySelector(el) : el
    this.el.addEventListener(&quot;touchmove&quot;, this.move, false)
    this.el.addEventListener(&quot;touchend&quot;, this.end, false)
    this.pressMove = new Observer(this.el)
    this.pressMove.add(option.pressMove || function () {})
  }
  move(evt) {
    if (!evt.touches) return
    let len = evt.touches.length
    if (len === 1) this.curV = {
      x: evt.touches[0].pageX,
      y: evt.touches[0].pageY
    }
  }
  end(evt) {
    evt.deltaX = this.curV.x
    evt.deltaY = this.curV.y
    evt.deltaX &amp;&amp; evt.deltaY &amp;&amp; this.pressMove.dispatch(evt, this.element);
  }
}</code></pre></div> <div class="css" data-v-2a5edddd></div></div></div> <h2 id="multipointend"><a href="#multipointend" class="header-anchor">#</a> MultipointEnd</h2> <div class="compare" data-v-2a5edddd><div class="left" data-v-2a5edddd><p data-v-2a5edddd>效果</p> <div class="jq" data-v-2a5edddd></div> <div class="effect" data-v-2a5edddd><img id="finger" src="/blog/images/IMG_8898.gif" data-v-2a5edddd></div></div> <div class="right" data-v-2a5edddd><p data-v-2a5edddd>模拟</p> <div class="js" data-v-2a5edddd><pre data-v-2a5edddd><code class="javascript" data-v-2a5edddd>class AlloyFinger{
    constructor(el, option) {
        this.el = typeof el == &quot;string&quot; ? document.querySelector(el) : el
        this.el.addEventListener(&quot;touchend&quot;, this.end, false)
        this.multipointEnd = new Observer(this.el)
        this.multipointEnd.add(option.multipointEnd || function () {})
    }
    end(evt) {
        if (!evt.changedTouches) return
        if (evt.touches.length &gt; 1) this.multipointEnd.dispatch(evt, this.el)
    }
}</code></pre></div> <div class="css" data-v-2a5edddd></div></div></div> <h2 id="doubletap"><a href="#doubletap" class="header-anchor">#</a> DoubleTap</h2> <div class="compare" data-v-2a5edddd><div class="left" data-v-2a5edddd><p data-v-2a5edddd>效果</p> <div class="jq" data-v-2a5edddd></div> <div class="effect" data-v-2a5edddd><img id="finger" src="/blog/images/IMG_8898.gif" data-v-2a5edddd></div></div> <div class="right" data-v-2a5edddd><p data-v-2a5edddd>模拟</p> <div class="js" data-v-2a5edddd><pre data-v-2a5edddd><code class="javascript" data-v-2a5edddd>class AlloyFinger {
  constructor(el, option) {
    this.el = typeof el == &quot;string&quot; ? document.querySelector(el) : el
    this.el.addEventListener(&quot;touchstart&quot;, this.start, false)
    this.el.addEventListener(&quot;touchmove&quot;, this.move, false)
    this.el.addEventListener(&quot;touchend&quot;, this.end, false)
    this.doubleTap = new Observer(this.el)
    this.doubleTap.add(option.doubleTap || function () {})
    this.tapPosition = {
      x: null,
      y: null
    }
    this.last = null;
  }
  start(evt) {
    if (!evt.touches) return
    let len = evt.touches.length
    if (len === 1) {
      this.x1 = evt.touches[0].pageX
      this.y1 = evt.touches[0].pageY
      this.now = Date.now();
      this.delta = this.now - (this.last || this.now);
      if (this.tapPosition.x !== null) {
        this.isDoubleTap = (this.delta &gt; 0 &amp;&amp; this.delta &lt;= 250 &amp;&amp; Math.abs(this.tapPosition.x - this.x1) &lt; 30 &amp;&amp; Math.abs(this.tapPosition.y - this.y1) &lt; 30)
      }
      this.tapPosition.x = this.x1
      this.tapPosition.y = this.y1
      this.last = this.now;
    }
  }
  move(evt) {
    if (!evt.touches) return
    let len = evt.touches.length
    this.isDoubleTap = false
    if (len === 1) {
      this.x2 = evt.touches[0].pageX;
      this.y2 = evt.touches[0].pageY;
    }
  }
  end(evt) {
    if (!evt.changedTouches) return
    if ((this.x2 &amp;&amp; Math.abs(this.x1 - this.x2) &lt;= 30) &amp;&amp;
      (this.y2 &amp;&amp; Math.abs(this.y1 - this.y2) &lt;= 30)) {
      if (this.isDoubleTap) {
        this.doubleTap.dispatch(evt, this.el);
        this.isDoubleTap = false;
      }
    }
  }
}</code></pre></div> <div class="css" data-v-2a5edddd></div></div></div> <h2 id="singletap"><a href="#singletap" class="header-anchor">#</a> SingleTap</h2> <div class="compare" data-v-2a5edddd><div class="left" data-v-2a5edddd><p data-v-2a5edddd>效果</p> <div class="jq" data-v-2a5edddd></div> <div class="effect" data-v-2a5edddd><img id="finger" src="/blog/images/IMG_8898.gif" data-v-2a5edddd></div></div> <div class="right" data-v-2a5edddd><p data-v-2a5edddd>模拟</p> <div class="js" data-v-2a5edddd><pre data-v-2a5edddd><code class="javascript" data-v-2a5edddd>class AlloyFinger {
  constructor(el, option) {
    this.el = typeof el == &quot;string&quot; ? document.querySelector(el) : el
    this.el.addEventListener(&quot;touchstart&quot;, this.start, false)
    this.el.addEventListener(&quot;touchmove&quot;, this.move, false)
    this.el.addEventListener(&quot;touchend&quot;, this.end, false)
    this.singleTap = new Observer(this.el)
    this.singleTap.add(option.singleTap || function () {})
    this.tapPosition = {
      x: null,
      y: null
    }
    this.last = null;
  }
  start(evt) {
    if (!evt.touches) return
    let len = evt.touches.length
    if (len === 1) {
      this.x1 = evt.touches[0].pageX
      this.y1 = evt.touches[0].pageY
      this.now = Date.now();
      this.delta = this.now - (this.last || this.now);
      if (this.tapPosition.x !== null) {
        this.isDoubleTap = (this.delta &gt; 0 &amp;&amp; this.delta &lt;= 250 &amp;&amp; Math.abs(this.tapPosition.x - this.x1) &lt; 30 &amp;&amp; Math.abs(this.tapPosition.y - this.y1) &lt; 30)
      }
      this.tapPosition.x = this.x1
      this.tapPosition.y = this.y1
      this.last = this.now;
    }
  }
  move(evt) {
    if (!evt.touches) return
    let len = evt.touches.length
    this.isDoubleTap = false
    if (len === 1) {
      this.x2 = evt.touches[0].pageX;
      this.y2 = evt.touches[0].pageY;
    }
  }
  end(evt) {
    if (!evt.changedTouches) return
    if ((this.x2 &amp;&amp; Math.abs(this.x1 - this.x2) &lt;= 30) &amp;&amp;
      (this.y2 &amp;&amp; Math.abs(this.y1 - this.y2) &lt;= 30)) {
      if (!this.isDoubleTap) {
        this.singleTap.dispatch(evt, this.el)
      }
    }
  }
}</code></pre></div> <div class="css" data-v-2a5edddd></div></div></div> <h2 id="touchstart"><a href="#touchstart" class="header-anchor">#</a> TouchStart</h2> <div class="compare" data-v-2a5edddd><div class="left" data-v-2a5edddd><p data-v-2a5edddd>效果</p> <div class="jq" data-v-2a5edddd></div> <div class="effect" data-v-2a5edddd><img id="finger" src="/blog/images/IMG_8898.gif" data-v-2a5edddd></div></div> <div class="right" data-v-2a5edddd><p data-v-2a5edddd>模拟</p> <div class="js" data-v-2a5edddd><pre data-v-2a5edddd><code class="javascript" data-v-2a5edddd>class AlloyFinger{
    constructor(el,option){
        this.el = typeof el == &quot;string&quot; ? document.querySelector(el) : el
        this.el.addEventListener(&quot;touchstart&quot;, this.start, false);
        this.touchStart = new Observer(this.el)
        this.touchStart.add(option.touchStart||function(){})
    }
    start(evt){
        if (!evt.touches) return
        this.touchStart.dispatch(evt, this.el)
    }
}</code></pre></div> <div class="css" data-v-2a5edddd></div></div></div> <h2 id="touchmove"><a href="#touchmove" class="header-anchor">#</a> TouchMove</h2> <div class="compare" data-v-2a5edddd><div class="left" data-v-2a5edddd><p data-v-2a5edddd>效果</p> <div class="jq" data-v-2a5edddd></div> <div class="effect" data-v-2a5edddd><img id="finger" src="/blog/images/IMG_8898.gif" data-v-2a5edddd></div></div> <div class="right" data-v-2a5edddd><p data-v-2a5edddd>模拟</p> <div class="js" data-v-2a5edddd><pre data-v-2a5edddd><code class="javascript" data-v-2a5edddd>class AlloyFinger {
  constructor(el, option) {
    this.el = typeof el == &quot;string&quot; ? document.querySelector(el) : el
    this.el.addEventListener(&quot;touchmove&quot;, this.move, false)
    this.el.addEventListener(&quot;touchend&quot;, this.end, false)
    this.pinch = new Observer(this.el)
    this.pinch.add(option.pinch || function () {})
  }
  move(evt) {
    if (!evt.touches) return
    let len = evt.touches.length
    if (len === 1) this.curV = {
      x: evt.touches[0].pageX,
      y: evt.touches[0].pageY
    }
  }
  end(evt) {
    this.curV.x &amp;&amp; this.touchMove.dispatch(evt, this.element)
  }
}</code></pre></div> <div class="css" data-v-2a5edddd></div></div></div> <h2 id="touchend"><a href="#touchend" class="header-anchor">#</a> TouchEnd</h2> <div class="compare" data-v-2a5edddd><div class="left" data-v-2a5edddd><p data-v-2a5edddd>效果</p> <div class="jq" data-v-2a5edddd></div> <div class="effect" data-v-2a5edddd><img id="finger" src="/blog/images/IMG_8898.gif" data-v-2a5edddd></div></div> <div class="right" data-v-2a5edddd><p data-v-2a5edddd>模拟</p> <div class="js" data-v-2a5edddd><pre data-v-2a5edddd><code class="javascript" data-v-2a5edddd>class AlloyFinger{
    constructor(el, option) {
        this.el = typeof el == &quot;string&quot; ? document.querySelector(el) : el
        this.el.addEventListener(&quot;touchend&quot;, this.end, false)
        this.touchEnd = new Observer(this.el)
        this.touchEnd.add(option.touchEnd || function () {})
    }
    end(evt) {
        if (!evt.changedTouches) return
        this.touchEnd.dispatch(evt, this.el);
    }
}</code></pre></div> <div class="css" data-v-2a5edddd></div></div></div> <h2 id="touchcancel"><a href="#touchcancel" class="header-anchor">#</a> TouchCancel</h2> <div class="compare" data-v-2a5edddd><div class="left" data-v-2a5edddd><p data-v-2a5edddd>效果</p> <div class="jq" data-v-2a5edddd></div> <div class="effect" data-v-2a5edddd><img id="finger" src="/blog/images/IMG_8898.gif" data-v-2a5edddd></div></div> <div class="right" data-v-2a5edddd><p data-v-2a5edddd>模拟</p> <div class="js" data-v-2a5edddd><pre data-v-2a5edddd><code class="javascript" data-v-2a5edddd>class AlloyFinger{
    constructor(el, option) {
        this.el = typeof el == &quot;string&quot; ? document.querySelector(el) : el
        this.el.addEventListener(&quot;touchcancel&quot;, this.cancel, false)
        this.touchCancel = new Observer(this.el)
        this.touchCancel.add(option.touchCancel || function () {})
    }
    cancel(evt) {
        this.touchCancel.dispatch(evt, this.el);
    }
}</code></pre></div> <div class="css" data-v-2a5edddd></div></div></div></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">上次更新:</span> <span class="time">2/17/2021, 11:27:55 PM</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
      ←
      <a href="/blog/dsm/lodash.html" class="prev">
        jQuery / Lodash
      </a></span> <!----></p></div> </main></div><div class="global-ui"><BackToTop></BackToTop><!----><Live2D></Live2D></div></div>
    <script src="/blog/assets/js/app.7fa07907.js" defer></script><script src="/blog/assets/js/2.b6c629b5.js" defer></script><script src="/blog/assets/js/15.e91e78ed.js" defer></script><script src="/blog/assets/js/4.1dbf8b08.js" defer></script><script src="/blog/assets/js/3.589a64d8.js" defer></script>
  </body>
</html>
